/*
 * Copyright 2016 Scalified <http://www.scalified.com>
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
//package com.scalified.tree.multinode;
package com.gitee.wsl.struct.tree.multinode

import com.gitee.wsl.struct.tree.CategoryTreeNode
import com.gitee.wsl.struct.tree.TreeNode
import com.gitee.wsl.struct.tree.TreeNodeException
import com.gitee.wsl.struct.tree.TreeNodeManager.areAllNulls

/**
 * This class represents the K-ary (multiple node) tree data
 * structure
 * <h1>Definition</h1>
 *
 *
 * **K-ary tree** - tree, in which each node has no more than k subtrees
 *
 * @author shell
 * @version 1.0.0
 * @since 1.0.0
 */
abstract class MultiTreeNode(data: Any) : CategoryTreeNode(data) /*implements TreeSeq<T,TreeNode<T>>*/ {
    /**
     * Adds the collection of the subtrees with all of theirs descendants
     * to the current tree node
     *
     *
     * Checks whether this tree node was changed as a result of the call
     *
     * @param subtrees collection of the subtrees with all of their
     * descendants
     * @return `true` if this tree node was changed as a
     * result of the call; `false` otherwise
     */
    open fun addSubtrees(subtrees: List<TreeNode>): Boolean {
        if (areAllNulls(subtrees)) {
            return false
        }
        for (subtree in subtrees) {
            //linkParent(subtree, this);
            if (!add(subtree)) {
                return false
            }
        }
        return true
    }

    /*abstract fun hasSubtree(subtree: TreeNode): Boolean
    
    abstract operator fun contains(node: TreeNode): Boolean
    
    abstract fun remove(node: TreeNode): Boolean*/
    
    //public abstract void traversePreOrder(TraversalAction<TreeNode> action);
    /**
     * Returns the collection of nodes, which have the same parent
     * as the current node; [Collections.emptyList] if the current
     * tree node is root or if the current tree node has no subtrees
     *
     * @return collection of nodes, which have the same parent as
     * the current node; [Collections.emptyList] if the
     * current tree node is root or if the current tree node has
     * no subtrees
     */
    fun siblings(): List<TreeNode> {
        if (isRoot) {
            val message = "Unable to find the siblings. The tree node ${root()} is root"
            throw TreeNodeException(message)
        }
        val parentSubtrees: List<TreeNode> = parent!!.subtrees()
        val parentSubtreesSize = parentSubtrees.size
        if (parentSubtreesSize == 1) {
            return emptyList()
        }
        val siblings = ArrayList<TreeNode>(parentSubtreesSize - 1)
        for (parentSubtree in parentSubtrees) {
            if (parentSubtree != this) {
                siblings.add(parentSubtree)
            }
        }
        return siblings
    }

    /**
     * Checks whether among the current tree node subtrees there are
     * all of the subtrees from the specified collection
     *
     * @param subtrees collection of subtrees to be checked for containment
     * within the current tree node subtrees
     * @return `true` if among the current tree node subtrees
     * there are all of the subtrees from the specified collection;
     * `false` otherwise
     */
    fun hasSubtrees(subtrees: List<TreeNode>): Boolean {
        if (isLeaf || areAllNulls(subtrees)) {
            return false
        }
        for (subtree in subtrees) {
            if (!this.hasSubtree(subtree)) {
                return false
            }
        }
        return true
    }

    /**
     * Removes all of the collection's subtrees from the current tree node
     *
     *
     * Checks whether the current tree node was changed as a result of
     * the call
     *
     * @param subtrees collection containing subtrees to be removed from the
     * current tree node
     * @return `true` if the current tree node was changed as a result
     * of the call; `false` otherwise
     */
    fun dropSubtrees(subtrees: List<TreeNode>): Boolean {
        if (isLeaf || areAllNulls(subtrees)) {
            return false
        }
        var result = false
        for (subtree in subtrees) {
            val currentResult = dropSubtree(subtree)
            if (!result && currentResult) {
                result = true
            }
        }
        return result
    }
}